from typing import Generator, Optional, List
from fastapi import Depends, HTTPException, status, Request
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError
from sqlalchemy.orm import Session
from app.core.config import settings
from app.core.security import ALGORITHM
from app.database.database import SessionLocal
from app.database.models.base import User, Role, RolePermission, Permission

oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.API_V1_STR}/auth/login")

def get_db() -> Generator:
    try:
        db = SessionLocal()
        yield db
    finally:
        db.close()

async def get_token_from_request(request: Request) -> Optional[str]:
    # 先从 header 中获取
    authorization = request.headers.get("Authorization")
    if authorization and authorization.startswith("Bearer "):
        return authorization.replace("Bearer ", "")
    
    # 如果 header 中没有，从 cookie 中获取
    cookie_auth = request.cookies.get("access_token")
    if cookie_auth and cookie_auth.startswith("Bearer "):
        return cookie_auth.replace("Bearer ", "")
    
    return None

async def get_current_user(
    request: Request,  # 添加这个参数
    db: Session = Depends(get_db),
) -> User:
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    
    token = await get_token_from_request(request)
    if not token:
        raise credentials_exception
        
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[ALGORITHM])
        user_id: str = payload.get("sub")
        if user_id is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    
    user = db.query(User).filter(User.id == int(user_id)).first()
    if user is None:
        raise credentials_exception
    return user

async def get_current_active_user(
    current_user: User = Depends(get_current_user),
) -> User:
    if not current_user.is_active:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user

def get_current_agent_user(
    current_user: User = Depends(get_current_active_user),
) -> User:
    if current_user.role not in ["admin", "agent"]:
        raise HTTPException(
            status_code=403,
            detail="The user doesn't have enough privileges"
        )
    return current_user

def get_user_permissions(db: Session, user: User) -> List[str]:
    """获取用户权限"""
    # 通过角色名称查找角色ID
    role = db.query(Role).filter(Role.name == user.role).first()
    if not role:
        return []
    
    # 手动关联查询权限
    permission_ids = db.query(RolePermission.permission_id)\
        .filter(RolePermission.role_id == role.id)\
        .all()
    
    permission_ids = [p[0] for p in permission_ids]
    
    permissions = db.query(Permission)\
        .filter(Permission.id.in_(permission_ids))\
        .all()
    
    return [p.code for p in permissions] 